<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>three</title>
    <style>
        body {
            background-color: #bfe3dd;
            color: #000;
            padding: 120px;
        }

    </style>
</head>

<body>
    <div class="canvas">
    </div>
    <!-- step1:引入插件 -->
    <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

    <script type="importmap">
  {
    "imports": {
      "three": "https://unpkg.com/three/build/three.module.js",
      "three/addons/": "https://unpkg.com/three/examples/jsm",
      "gui":"https://unpkg.com/three/examples/jsm/libs/lil-gui.module.min.js",
      "OrbitControls":"https://unpkg.com/three/examples/jsm/controls/OrbitControls.js",
       "GLTFLoader":"https://unpkg.com/three/examples/jsm/loaders/GLTFLoader",
       "ik":"https://unpkg.com/three/examples/jsm/animation/CCDIKSolver.js",
       "tran":"https://unpkg.com/three/examples/jsm/controls/TransformControls.js"
     
    }
  }
</script>
    <script type="module">
        import * as THREE from 'three';
        import { GUI } from "gui";
        import { OrbitControls } from "OrbitControls"
   
        import { GLTFLoader } from 'GLTFLoader';
        import { CCDIKSolver, CCDIKHelper } from 'ik';
        import { TransformControls } from 'tran';
        // import { CCDIKSolver, CCDIKHelper } from './jsm/animation/CCDIKSolver.js';
   
        console.log(THREE)

        // var loader = new THREE.FontLoader();
        // console.log(THREE.FontLoader)
        let nodeBody = {}
        let skeleton
        let skeletonPos = []
        const clock = new THREE.Clock();
        let mixer
        let actions = []; //所有的动画数组

        const v0 = new THREE.Vector3();
   
        var worldPosition = new THREE.Vector3();
        let meshArr =[]
        let skeletionArr = []
      
        // 将object作为子级来添加到该对象中，同时保持该object的世界变换。
        // nodeBody.head.attach( nodeBody.eyes );
        // model.scale.set(1,1, 1);
        let conf = {
				followSphere: false,
				turnHead: true,
				ik_solver:false,
			};
       
        class threeInit {
            constructor(param) {
                this.param = {
                    x: 0,
                    y: 0,
                    z: 0
                }
                this.initScene()
                this.initLight()
                this.initObject()
                this.initCamera()
                
            }
            // 初始化物体
            async initObject() {
                //材质
                // let material = new THREE.MeshLambertMaterial({
                //     color: 0x05c5cf4
                // });
                // let geometry = new THREE.BoxGeometry(100, 100, 100); //创建一个立方体几何对象Geometry
                // this.mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
                // this.mesh.position.set(this.param.x, this.param.y, this.param.z)
                let that = this
                function initModel(url) {
                    
                    return new Promise(async (resolve)=>{
                        let singleMergeMesh
                        const gltfLoader = new GLTFLoader();
                        const gltf = await gltfLoader.loadAsync( './family.gltf' );
                        // conso
            
                        gltf.scene.traverse( res => {
                            // res.position = res.getWorldPosition(worldPosition)
                            // res.parent =
                            console.log("这个可以看出名字和骨骼-n.skeleton有两个类型 SkinnedMesh(传入ccdik的参数) | Skeleton(c4d的骨骼):", res.name, res.skeleton)
                        if(res.name && res.skeleton){
                            nodeBody.hands = res
                            //重要： ccd ik 的 第一个参数
                           
                            var worldPosition = new THREE.Vector3();
                        that.initVisSprite(res.name, [res.getWorldPosition(worldPosition).x+0.2, res.getWorldPosition(worldPosition).y, res.getWorldPosition(worldPosition).z])
                        }else{
                            console.log("19:41",res.name,res.skeleton)
                        }
                        if(res.name=="关节"){
                            
                        }
                        if(res.name=="关节3"){
                            nodeBody.hands_control = res
                        }
                        // var worldPosition = new THREE.Vector3();
                        // that.initVisSprite(res.name, [res.getWorldPosition(worldPosition).x+0.2, res.getWorldPosition(worldPosition).y, res.getWorldPosition(worldPosition).z])
                        });


                        
                       
                        // 
                    // if (res.isMesh) res.frustumCulled = false;


                        resolve(gltf)
                    })
                
                
                }
        let model = await initModel();
                // this.scene.add(this.mesh)
                this.mesh = model.scene
                console.log("模型",model)
                model.scene.traverse( res => {
                    // var worldPosition = new THREE.Vector3();
                    // console.log("inn",res.name,res.getWorldPosition(worldPosition))
           
                    // res.position.x = res.getWorldPosition(worldPosition).x
                    // res.position.y = res.getWorldPosition(worldPosition).y
                    // res.position.z = res.getWorldPosition(worldPosition).z
                    // res.scale.set(1,1,1)
                    // this.initVisSprite(res.name,[res.getWorldPosition(worldPosition).x,res.getWorldPosition(worldPosition).y,res.getWorldPosition(worldPosition).z])
                } );
                // model.scene.scale.set(10,10,10)
                // console.log("模型：",model.scene)
                let skeleton = new THREE.SkeletonHelper(model.scene);
                this.scene.add(skeleton);
                this.initBones()
                this.scene.add(model.scene)
               
            }
            initScene() {
                this.scene = new THREE.Scene()
                const group = new THREE.Group();
				this.scene.add( group );
                const helper = new THREE.GridHelper( 160, 100 );
				// helper.rotation.x = Math.PI / 2;
				group.add( helper );
            }
            initLight() {
                let pointLight = new THREE.PointLight(0xffffff); //创建一个白色的点光源
                pointLight.position.set(0, 0, 150);
                this.scene.add(pointLight);
                let ambient = new THREE.AmbientLight(0xffffff, 1);
                this.scene.add(ambient);
                //                 const skyColor = 0xB1E1FF;  // bleu
                //   const groundColor = 0xB97A20;  // orange brun
                //   const intensity = 2;
                //                 const light = new THREE.HemisphereLight(skyColor, groundColor, intensity);
                //                 this.scene.add(light);
            }
            initCamera() {
                this.width = 1280; //canvas画布宽度
                this.height = 600; //canvas画布高度
                let k = this.width / this.height; //canvas画布宽高比
                //三维场景显示范围控制系数，系数越大，显示的范围越大
                //创建相机对象
                this.camera = new THREE.PerspectiveCamera(30, k, 20, 10000);
                this.camera.position.set(-30, 50,30); //设置相机位置
                let v1 = new THREE.Vector3(0, 0, 0)
                this.camera.lookAt(v1); //设置相机方向(指向的场景对象)
            }
            initGui(status) {

                //1.设置基本属性
                let gui = new GUI();
                gui.domElement.classList.add();
                gui.domElement.style.cssText = "position:absolute;top:0px;right:0px;";
                // 2.等于params.x的属性跟mesh.position.y绑定
                //-3 到 3 每一次0.01  mesh.position.x
                gui.add(this.param, 'x', -3, 100, 0.01)
                    .onChange(() => {
                        this.mesh.position.x = this.param.x;
                    }).name('x的位置')

                gui.add(this.param, 'y', -3, 100, 0.01)
                    .onChange(() => {
                        this.mesh.position.y = this.param.y;
                    }).name('y的位置(上下)')

                gui.add(this.param, 'z', -3, 100, 0.01)
                    .onChange(() => {
                        this.mesh.position.z = this.param.z;
                    }).name('z的位置')
                // gui.add(params, 'wireframe', [true, false])
                //     .onChange(function () {
                //         material.wireframe = params.wireframe;
                //     }).name('设置线框')


                // // gui.add(material, 'wireframe').name('设置线框')
                // // gui.add(params,'background').name('设置天空')
                // //gui.addColor
                // gui.addColor(params, 'color')
                //     .onChange(function () {
                //         material.color.set(params.color);
                //     });

                // //2.重要：实现切换天空的效果
                // gui.add(params, 'background', ["sky", "home"])
                //     .onChange(function () {
                //         initskyboxsun25deg(params.background);
                //     }).name("切换天空");
            }
            initSkyBox() {

                const starUrls = [
                    ("https://cdn.jsdelivr.net/npm/electroluxasset/skybox/skyboxsun25deg/px.jpg"), // right
                    ("https://cdn.jsdelivr.net/npm/electroluxasset/skybox/skyboxsun25deg/nx.jpg"), // left
                    ("https://cdn.jsdelivr.net/npm/electroluxasset/skybox/skyboxsun25deg/py.jpg"), // top
                    ("https://cdn.jsdelivr.net/npm/electroluxasset/skybox/skyboxsun25deg/ny.jpg"), // bottom
                    ("https://cdn.jsdelivr.net/npm/electroluxasset/skybox/skyboxsun25deg/pz.jpg"), // back
                    ("https://cdn.jsdelivr.net/npm/electroluxasset/skybox/skyboxsun25deg/nz.jpg"), // front
                ];
                this.scene.background = new THREE.CubeTextureLoader().load(starUrls);


            }
            initVisSprite(text,pos){
                function canvasMed(canvas, param, content) {
                    const ctl1 = canvas
        
                    ctl1.fillStyle = "rgba(255, 255, 153, 1.0)";
                    ctl1.fillRect(0, 0, param.width, param.height);
                    ctl1.textAlign = "center";
                    ctl1.textBaseline = "middle";
                    ctl1.font = "bold 12px Arial";
                    // ctl1.lineWidth = 26;
                    ctl1.fillStyle = "rgba(25, 25, 25, 1.0)";
                    ctl1.fillText(content, param.x, param.y);
                

                }
                if(!text || !pos){
                    return
                }
            
                let dynamicSprite
                const canvas = document.createElement("canvas");
                
                let panel = canvas.getContext('2d')

                var param = {
                    width: 150,
                    height: 40,
                    text: "",
                    name: "dynamicLabel",
                    x: 75,
                    y: 20,
                 
                };
                param.text = text
                canvas.height = param.height;
                canvas.width = param.width;
            
                canvasMed(panel, param, param.text);
                var texture = new THREE.Texture(canvas);
                texture.needsUpdate = true;
                //定义一个精灵
                const spriteMaterial = new THREE.SpriteMaterial({
                    map: texture
                });
                dynamicSprite = new THREE.Sprite(spriteMaterial);
                dynamicSprite.position.set(
                    // 重要这里因人而异
                    pos[0],pos[1]+Math.random()*10,pos[2]+Math.random()*20
                );
                dynamicSprite.name = "你好";
                // 重要这里因人而异
                dynamicSprite.scale.set(10, 3, 10);
                this.scene.add(dynamicSprite)
            }

            initBones(){
                 // 这里是IK的第一个参数个第二个参数
                // console.log("nodeBody:",nodeBody.hands,skeletionArr)
            
                // 
                // const iks = [
                //     {
                //         target: 35, // "mixamorig_Rightshoulder 最顶点"  4. 最外面的一根手指
                //         effector:34 , // 拇指给一个 1  
                //         links: [
                //             {
                //                 // 链接的骨骼 low
                //                 index: 33, // "mixamorig_RightForeArm" 父  parent 是 RightArm
                //                 // 第一个参数上下  第二个参数前后 
                //                 // rotationMin: new THREE.Vector3( -100, 60, -0 ),
				// 			    // rotationMax: new THREE.Vector3( -100, 60, 0),
                //                 // minAngle:"1deg",
                //                 // minAngle:0.2,
                //                 // maxAngle:0.2
                //             },
                            
                //             {
                //                 index: 32, //"mixamorig_RightArm" 手腕 hight    parent 是 shoulder
                //                 // rotationMin: new THREE.Vector3( 50, 0, -10 ),
				// 			    // rotationMax: new THREE.Vector3( 50, 60, 20),
                //                 // minAngle:0.8
                //                 // maxAngle:0.2
                //                 // minAngle:0.2,
                //                 // maxAngle:0.2
                //             },
                //             {
                //                 index: 31, //"mixamorig_RightArm" 手腕 hight    parent 是 shoulder
                //                 // rotationMin: new THREE.Vector3( 50, 0, -10 ),
				// 			    // rotationMax: new THREE.Vector3( 50, 60, 20),
                //                 // minAngle:0.8
                //                 // maxAngle:0.2
                //                 // minAngle:0.2,
                //                 // maxAngle:0.2
                //             },
                //         ],
                //     }
                // ];

                const iks = [
                    {
                        target: 0, // "mixamorig_Rightshoulder 最顶点"  4. 最外面的一根手指
                        effector:3 , // 拇指给一个 1  
                        links: [
                        {
                                // 链接的骨骼 low
                                index:1, // "mixamorig_RightForeArm" 父  parent 是 RightArm
                                // rotationMin: new THREE.Vector3( 0, -0.1, -0 ),
							    // rotationMax: new THREE.Vector3( 0.2, 100, 0),
                                // maxAngle:0.2,
                                // minAngle:0.2,
                            },
                            {
                                // 链接的骨骼 low
                                index:2, // "mixamorig_RightForeArm" 父  parent 是 RightArm
                                // rotationMin: new THREE.Vector3( 0, -0.1, -0 ),
							    // rotationMax: new THREE.Vector3( 0.2, 100, 0),
                                // maxAngle:0.2,
                                // minAngle:0.2,
                            },
                            
                            // {
                            //     // 链接的骨骼 low
                            //     index: 31, // "mixamorig_RightForeArm" 父  parent 是 RightArm
                              
                            // },
                            // {
                            //     // 链接的骨骼 low
                            //     index: 3, // "mixamorig_RightForeArm" 父  parent 是 RightArm
                              
                            // },
                        ],
                    }
                ];
                
                // 第一个值传入蒙皮但是这个值好难控制
                console.log("nodeBody.hands",nodeBody.hands)
                // this.IKSolver = new CCDIKSolver( nodeBody.hands, iks );
                // this.IKSolver.update()   
                console.log("ccd ik 的 第一个参数",nodeBody.hands)
                const ccdikhelper = new CCDIKHelper( nodeBody.hands, iks,  );

                // console.log(nodeBody.control.position)
               
                let temp = 0
                // nodeBody.control.position.z =temp+3
                
                setInterval(() => {
                    // res.position = res.getWorldPosition(worldPosition)
                    // temp = temp+1.5
                    // nodeBody.control.getWorldPosition(worldPosition).y = temp
                    // console.log( nodeBody.control.getWorldPosition(worldPosition))
                    if(temp<20){
                        // nodeBody.control_target.position.x = nodeBody.control_target.position.x+1
                        temp = temp +1
                    }
                    
                    // nodeBody.control.rotateX = nodeBody.control.rotateX + 3 
                    // nodeBody.control.position.y = nodeBody.control.position.y-1
                 }, 1000);

                console.log("19:40",nodeBody)
			    this.scene.add( ccdikhelper );

               
            }

            initRender() {
                // this.initVisSprite()
                let v1 = new THREE.Vector3(0, 0, 0)
                // let renderer = new THREE.WebGLRenderer();
                this.renderer = new THREE.WebGLRenderer({ alpha: true });
                this.renderer.setSize(this.width, this.height);//设置渲染区域尺寸

                // 添加控制器
                let control = new OrbitControls(this.camera, this.renderer.domElement);
                control.target = v1 //设置相机方向(指向的场景对象)
                

                let transformControls = new TransformControls( this.camera, this.renderer.domElement );
                transformControls.size = 1.15;
                // transformControls.showX = false;
                transformControls.space = 'world';
                transformControls.attach( nodeBody.hands_control );
                // transformControls.position.y =+60
              
                this.scene.add( transformControls );
                transformControls.addEventListener( 'mouseDown', () => control.enabled = false );
			    transformControls.addEventListener( 'mouseUp', () => control.enabled = true );


                
                // renderer.setClearColor(0xb9d3ff, 1);
                // 渲染函数
                let render = () => {
                    // actions[0].play();
                    // const delta = clock.getDelta();
                    // if ( mixer ) mixer.update( delta );

                    if ( !conf.ik_solver ) {

                        if ( this.IKSolver ) this.IKSolver.update();
                    }
                    this.camera.updateProjectionMatrix();
                    // control.update();
                    // this.mesh.rotateY(0.01);//每次绕y轴旋转0.01弧度
                    this.renderer.render(this.scene, this.camera);//执行渲染操作
                    // mesh.rotateY(0.01);//每次绕y轴旋转0.01弧度
                   
                    requestAnimationFrame(render);//请求再次执行渲染函数render，渲染下一帧
                }
                render();
                return  this.renderer
            }


        }

        let three = new threeInit()
        three.initGui(1)

        
       
     

       
        // setInterval(() => {
        //     canvasMed(panel, param,`${Math.round(Math.random() * 60)}M/s`);
        //     dynamicSprite.material.map.needsUpdate = true;
        // }, 1000);


        // 重要。添加骨架
        // three.scene.add(skeleton)
        // three.initSkyBox()

        setTimeout(() => {
            document.querySelector('.canvas').appendChild(three.initRender().domElement);
        }, 1000);


        // let change=(status)=>{
        //     let render = (status) => {
        //             actions[status].play();
                    
        //             // mesh.rotateY(0.01);//每次绕y轴旋转0.01弧度
        //             requestAnimationFrame(render(status));//请求再次执行渲染函数render，渲染下一帧
        //         }
        //     render(status);
        // }
        // change(16)
        // function createAction(i){
        //         // actions[i] = mixer.clipAction(mesh.animations[i]);
        //         console.log(actions)
        //         for(var j=0; j<actions.length; j++){
        //                 if(j == i){
        //                     actions[j].play();
        //                 }
        //                 else{
        //                     actions[j].stop();
        //                 }
        //             }

               
        //     }
        //     createAction(2)
    </script>

</body>

</html>